{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp data.external"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# External data\n",
    "\n",
    "> Helper functions used to download and extract common time series datasets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from tsai.imports import *\n",
    "from tsai.utils import * \n",
    "from tsai.data.validation import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "# Fix to fastai issue #3485 (not deployed to pip yet)\n",
    "if not hasattr(pd.DataFrame,'_old_init'): pd.DataFrame._old_init = pd.DataFrame.__init__\n",
    "    \n",
    "@patch\n",
    "def __init__(self:pd.DataFrame, data=None, index=None, columns=None, dtype=None, copy=None):\n",
    "    if data is not None and isinstance(data, Tensor): data = to_np(data)\n",
    "    self._old_init(data, index=index, columns=columns, dtype=dtype, copy=copy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from sktime.utils.data_io import load_from_tsfile_to_dataframe as ts2df\n",
    "from sktime.utils.validation.panel import check_X\n",
    "from sktime.utils.data_io import TsFileParseException"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from fastai.data.external import *\n",
    "from tqdm import tqdm\n",
    "import zipfile\n",
    "import tempfile\n",
    "try: from urllib import urlretrieve\n",
    "except ImportError: from urllib.request import urlretrieve\n",
    "import shutil\n",
    "from numpy import distutils\n",
    "import distutils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def decompress_from_url(url, target_dir=None, verbose=False):\n",
    "    # Download\n",
    "    try:\n",
    "        pv(\"downloading data...\", verbose)\n",
    "        fname = os.path.basename(url)\n",
    "        tmpdir = tempfile.mkdtemp()\n",
    "        tmpfile = os.path.join(tmpdir, fname)\n",
    "        urlretrieve(url, tmpfile)\n",
    "        pv(\"...data downloaded\", verbose)\n",
    "\n",
    "        # Decompress\n",
    "        try:\n",
    "            pv(\"decompressing data...\", verbose)\n",
    "            if not os.path.exists(target_dir): os.makedirs(target_dir)\n",
    "            shutil.unpack_archive(tmpfile, target_dir)\n",
    "            shutil.rmtree(tmpdir)\n",
    "            pv(\"...data decompressed\", verbose)\n",
    "            return target_dir\n",
    "        \n",
    "        except:\n",
    "            shutil.rmtree(tmpdir)\n",
    "            if verbose: sys.stderr.write(\"Could not decompress file, aborting.\\n\")\n",
    "\n",
    "    except:\n",
    "        shutil.rmtree(tmpdir)\n",
    "        if verbose:\n",
    "            sys.stderr.write(\"Could not download url. Please, check url.\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from fastdownload import download_url\n",
    "def download_data(url, fname=None, c_key='archive', force_download=False, timeout=4, verbose=False):\n",
    "    \"Download `url` to `fname`.\"\n",
    "    fname = Path(fname or URLs.path(url, c_key=c_key))\n",
    "    fname.parent.mkdir(parents=True, exist_ok=True)\n",
    "    if not fname.exists() or force_download: download_url(url, dest=fname, timeout=timeout, show_progress=verbose)\n",
    "    return fname"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "def get_UCR_univariate_list():\n",
    "    return [\n",
    "        'ACSF1', 'Adiac', 'AllGestureWiimoteX', 'AllGestureWiimoteY',\n",
    "        'AllGestureWiimoteZ', 'ArrowHead', 'Beef', 'BeetleFly', 'BirdChicken',\n",
    "        'BME', 'Car', 'CBF', 'Chinatown', 'ChlorineConcentration',\n",
    "        'CinCECGTorso', 'Coffee', 'Computers', 'CricketX', 'CricketY',\n",
    "        'CricketZ', 'Crop', 'DiatomSizeReduction',\n",
    "        'DistalPhalanxOutlineAgeGroup', 'DistalPhalanxOutlineCorrect',\n",
    "        'DistalPhalanxTW', 'DodgerLoopDay', 'DodgerLoopGame',\n",
    "        'DodgerLoopWeekend', 'Earthquakes', 'ECG200', 'ECG5000', 'ECGFiveDays',\n",
    "        'ElectricDevices', 'EOGHorizontalSignal', 'EOGVerticalSignal',\n",
    "        'EthanolLevel', 'FaceAll', 'FaceFour', 'FacesUCR', 'FiftyWords',\n",
    "        'Fish', 'FordA', 'FordB', 'FreezerRegularTrain', 'FreezerSmallTrain',\n",
    "        'Fungi', 'GestureMidAirD1', 'GestureMidAirD2', 'GestureMidAirD3',\n",
    "        'GesturePebbleZ1', 'GesturePebbleZ2', 'GunPoint', 'GunPointAgeSpan',\n",
    "        'GunPointMaleVersusFemale', 'GunPointOldVersusYoung', 'Ham',\n",
    "        'HandOutlines', 'Haptics', 'Herring', 'HouseTwenty', 'InlineSkate',\n",
    "        'InsectEPGRegularTrain', 'InsectEPGSmallTrain', 'InsectWingbeatSound',\n",
    "        'ItalyPowerDemand', 'LargeKitchenAppliances', 'Lightning2',\n",
    "        'Lightning7', 'Mallat', 'Meat', 'MedicalImages', 'MelbournePedestrian',\n",
    "        'MiddlePhalanxOutlineAgeGroup', 'MiddlePhalanxOutlineCorrect',\n",
    "        'MiddlePhalanxTW', 'MixedShapesRegularTrain', 'MixedShapesSmallTrain',\n",
    "        'MoteStrain', 'NonInvasiveFetalECGThorax1',\n",
    "        'NonInvasiveFetalECGThorax2', 'OliveOil', 'OSULeaf',\n",
    "        'PhalangesOutlinesCorrect', 'Phoneme', 'PickupGestureWiimoteZ',\n",
    "        'PigAirwayPressure', 'PigArtPressure', 'PigCVP', 'PLAID', 'Plane',\n",
    "        'PowerCons', 'ProximalPhalanxOutlineAgeGroup',\n",
    "        'ProximalPhalanxOutlineCorrect', 'ProximalPhalanxTW',\n",
    "        'RefrigerationDevices', 'Rock', 'ScreenType', 'SemgHandGenderCh2',\n",
    "        'SemgHandMovementCh2', 'SemgHandSubjectCh2', 'ShakeGestureWiimoteZ',\n",
    "        'ShapeletSim', 'ShapesAll', 'SmallKitchenAppliances', 'SmoothSubspace',\n",
    "        'SonyAIBORobotSurface1', 'SonyAIBORobotSurface2', 'StarLightCurves',\n",
    "        'Strawberry', 'SwedishLeaf', 'Symbols', 'SyntheticControl',\n",
    "        'ToeSegmentation1', 'ToeSegmentation2', 'Trace', 'TwoLeadECG',\n",
    "        'TwoPatterns', 'UMD', 'UWaveGestureLibraryAll', 'UWaveGestureLibraryX',\n",
    "        'UWaveGestureLibraryY', 'UWaveGestureLibraryZ', 'Wafer', 'Wine',\n",
    "        'WordSynonyms', 'Worms', 'WormsTwoClass', 'Yoga'\n",
    "    ]\n",
    "\n",
    "\n",
    "test_eq(len(get_UCR_univariate_list()), 128)\n",
    "UTSC_datasets = get_UCR_univariate_list()\n",
    "UCR_univariate_list = get_UCR_univariate_list()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "158"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#export\n",
    "def get_UCR_multivariate_list():\n",
    "    return [\n",
    "        'ArticularyWordRecognition', 'AtrialFibrillation', 'BasicMotions',\n",
    "        'CharacterTrajectories', 'Cricket', 'DuckDuckGeese', 'EigenWorms',\n",
    "        'Epilepsy', 'ERing', 'EthanolConcentration', 'FaceDetection',\n",
    "        'FingerMovements', 'HandMovementDirection', 'Handwriting', 'Heartbeat',\n",
    "        'InsectWingbeat', 'JapaneseVowels', 'Libras', 'LSST', 'MotorImagery',\n",
    "        'NATOPS', 'PEMS-SF', 'PenDigits', 'PhonemeSpectra', 'RacketSports',\n",
    "        'SelfRegulationSCP1', 'SelfRegulationSCP2', 'SpokenArabicDigits',\n",
    "        'StandWalkJump', 'UWaveGestureLibrary'\n",
    "    ]\n",
    "\n",
    "test_eq(len(get_UCR_multivariate_list()), 30)\n",
    "MTSC_datasets = get_UCR_multivariate_list()\n",
    "UCR_multivariate_list = get_UCR_multivariate_list()\n",
    "\n",
    "UCR_list = sorted(UCR_univariate_list + UCR_multivariate_list)\n",
    "classification_list = UCR_list\n",
    "TSC_datasets = classification_datasets = UCR_list\n",
    "len(UCR_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "hide_input": false
   },
   "outputs": [],
   "source": [
    "#export\n",
    "def get_UCR_data(dsid, path='.', parent_dir='data/UCR', on_disk=True, mode='c', Xdtype='float32', ydtype=None, return_split=True, split_data=True, \n",
    "                 force_download=False, verbose=False):\n",
    "    dsid_list = [ds for ds in UCR_list if ds.lower() == dsid.lower()]\n",
    "    assert len(dsid_list) > 0, f'{dsid} is not a UCR dataset'\n",
    "    dsid = dsid_list[0]\n",
    "    return_split = return_split and split_data # keep return_split for compatibility. It will be replaced by split_data\n",
    "    if dsid in ['InsectWingbeat']:\n",
    "        warnings.warn(f'Be aware that download of the {dsid} dataset is very slow!')\n",
    "    pv(f'Dataset: {dsid}', verbose)\n",
    "    full_parent_dir = Path(path)/parent_dir\n",
    "    full_tgt_dir = full_parent_dir/dsid\n",
    "#     if not os.path.exists(full_tgt_dir): os.makedirs(full_tgt_dir)\n",
    "    full_tgt_dir.parent.mkdir(parents=True, exist_ok=True)\n",
    "    if force_download or not all([os.path.isfile(f'{full_tgt_dir}/{fn}.npy') for fn in ['X_train', 'X_valid', 'y_train', 'y_valid', 'X', 'y']]):\n",
    "        # Option A\n",
    "        src_website = 'http://www.timeseriesclassification.com/Downloads'\n",
    "        decompress_from_url(f'{src_website}/{dsid}.zip', target_dir=full_tgt_dir, verbose=verbose)\n",
    "        if dsid == 'DuckDuckGeese':\n",
    "            with zipfile.ZipFile(Path(f'{full_parent_dir}/DuckDuckGeese/DuckDuckGeese_ts.zip'), 'r') as zip_ref:\n",
    "                zip_ref.extractall(Path(parent_dir))\n",
    "        if not os.path.exists(full_tgt_dir/f'{dsid}_TRAIN.ts') or not os.path.exists(full_tgt_dir/f'{dsid}_TRAIN.ts') or \\\n",
    "        Path(full_tgt_dir/f'{dsid}_TRAIN.ts').stat().st_size == 0 or Path(full_tgt_dir/f'{dsid}_TEST.ts').stat().st_size == 0: \n",
    "            print('It has not been possible to download the required files')\n",
    "            if return_split:\n",
    "                return None, None, None, None\n",
    "            else:\n",
    "                return None, None, None\n",
    "    \n",
    "        pv('loading ts files to dataframe...', verbose)\n",
    "        X_train_df, y_train = ts2df(full_tgt_dir/f'{dsid}_TRAIN.ts')\n",
    "        X_valid_df, y_valid = ts2df(full_tgt_dir/f'{dsid}_TEST.ts')\n",
    "        pv('...ts files loaded', verbose)\n",
    "        pv('preparing numpy arrays...', verbose)\n",
    "        X_train_ = []\n",
    "        X_valid_ = []\n",
    "        for i in progress_bar(range(X_train_df.shape[-1]), display=verbose, leave=False):\n",
    "            X_train_.append(stack_pad(X_train_df[f'dim_{i}'])) # stack arrays even if they have different lengths\n",
    "            X_valid_.append(stack_pad(X_valid_df[f'dim_{i}'])) # stack arrays even if they have different lengths\n",
    "        X_train = np.transpose(np.stack(X_train_, axis=-1), (0, 2, 1))\n",
    "        X_valid = np.transpose(np.stack(X_valid_, axis=-1), (0, 2, 1))\n",
    "        X_train, X_valid = match_seq_len(X_train, X_valid) \n",
    "    \n",
    "        np.save(f'{full_tgt_dir}/X_train.npy', X_train)\n",
    "        np.save(f'{full_tgt_dir}/y_train.npy', y_train)\n",
    "        np.save(f'{full_tgt_dir}/X_valid.npy', X_valid)\n",
    "        np.save(f'{full_tgt_dir}/y_valid.npy', y_valid)\n",
    "        np.save(f'{full_tgt_dir}/X.npy', concat(X_train, X_valid))\n",
    "        np.save(f'{full_tgt_dir}/y.npy', concat(y_train, y_valid))\n",
    "        del X_train, X_valid, y_train, y_valid\n",
    "        delete_all_in_dir(full_tgt_dir, exception='.npy')\n",
    "        pv('...numpy arrays correctly saved', verbose)\n",
    "\n",
    "    mmap_mode = mode if on_disk else None\n",
    "    X_train = np.load(f'{full_tgt_dir}/X_train.npy', mmap_mode=mmap_mode)\n",
    "    y_train = np.load(f'{full_tgt_dir}/y_train.npy', mmap_mode=mmap_mode)\n",
    "    X_valid = np.load(f'{full_tgt_dir}/X_valid.npy', mmap_mode=mmap_mode)\n",
    "    y_valid = np.load(f'{full_tgt_dir}/y_valid.npy', mmap_mode=mmap_mode)\n",
    "\n",
    "    if return_split:\n",
    "        if Xdtype is not None: \n",
    "            X_train = X_train.astype(Xdtype)\n",
    "            X_valid = X_valid.astype(Xdtype)\n",
    "        if ydtype is not None: \n",
    "            y_train = y_train.astype(ydtype)\n",
    "            y_valid = y_valid.astype(ydtype)\n",
    "        if verbose:\n",
    "            print('X_train:', X_train.shape)\n",
    "            print('y_train:', y_train.shape)\n",
    "            print('X_valid:', X_valid.shape)\n",
    "            print('y_valid:', y_valid.shape, '\\n')\n",
    "        return X_train, y_train, X_valid, y_valid\n",
    "    else:\n",
    "        X = np.load(f'{full_tgt_dir}/X.npy', mmap_mode=mmap_mode)\n",
    "        y = np.load(f'{full_tgt_dir}/y.npy', mmap_mode=mmap_mode)\n",
    "        splits = get_predefined_splits(X_train, X_valid)\n",
    "        if Xdtype is not None: \n",
    "            X = X.astype(Xdtype)\n",
    "        if verbose:\n",
    "            print('X      :', X .shape)\n",
    "            print('y      :', y .shape)\n",
    "            print('splits :', coll_repr(splits[0]), coll_repr(splits[1]), '\\n')\n",
    "        return X, y, splits\n",
    "    \n",
    "    \n",
    "get_classification_data = get_UCR_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ECGFiveDays\n",
      "AtrialFibrillation\n"
     ]
    }
   ],
   "source": [
    "#hide\n",
    "PATH = Path('.')\n",
    "dsids = ['ECGFiveDays', 'AtrialFibrillation'] # univariate and multivariate\n",
    "for dsid in dsids:\n",
    "    print(dsid)\n",
    "    tgt_dir = PATH/f'data/UCR/{dsid}'\n",
    "    if os.path.isdir(tgt_dir): shutil.rmtree(tgt_dir)\n",
    "    test_eq(len(get_files(tgt_dir)), 0) # no file left\n",
    "    X_train, y_train, X_valid, y_valid = get_UCR_data(dsid)\n",
    "    test_eq(len(get_files(tgt_dir, '.npy')), 6)\n",
    "    test_eq(len(get_files(tgt_dir, '.npy')), len(get_files(tgt_dir))) # test no left file/ dir\n",
    "    del X_train, y_train, X_valid, y_valid\n",
    "    start = time.time()\n",
    "    X_train, y_train, X_valid, y_valid = get_UCR_data(dsid)\n",
    "    elapsed = time.time() - start\n",
    "    test_eq(elapsed < 1, True)\n",
    "    test_eq(X_train.ndim, 3)\n",
    "    test_eq(y_train.ndim, 1)\n",
    "    test_eq(X_valid.ndim, 3)\n",
    "    test_eq(y_valid.ndim, 1)\n",
    "    test_eq(len(get_files(tgt_dir, '.npy')), 6)\n",
    "    test_eq(len(get_files(tgt_dir, '.npy')), len(get_files(tgt_dir))) # test no left file/ dir\n",
    "    test_eq(X_train.ndim, 3)\n",
    "    test_eq(y_train.ndim, 1)\n",
    "    test_eq(X_valid.ndim, 3)\n",
    "    test_eq(y_valid.ndim, 1)\n",
    "    test_eq(X_train.dtype, np.float32)\n",
    "    test_eq(X_train.__class__.__name__, 'memmap')\n",
    "    del X_train, y_train, X_valid, y_valid\n",
    "    X_train, y_train, X_valid, y_valid = get_UCR_data(dsid, on_disk=False)\n",
    "    test_eq(X_train.__class__.__name__, 'ndarray')\n",
    "    del X_train, y_train, X_valid, y_valid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train, y_train, X_valid, y_valid = get_UCR_data('natops')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset: NATOPS\n",
      "X_train: (180, 24, 51)\n",
      "y_train: (180,)\n",
      "X_valid: (180, 24, 51)\n",
      "y_valid: (180,) \n",
      "\n"
     ]
    }
   ],
   "source": [
    "dsid = 'natops' \n",
    "X_train, y_train, X_valid, y_valid = get_UCR_data(dsid, verbose=True)\n",
    "X, y, splits = get_UCR_data(dsid, split_data=False)\n",
    "test_eq(X[splits[0]], X_train)\n",
    "test_eq(y[splits[1]], y_valid)\n",
    "test_eq(X[splits[0]], X_train)\n",
    "test_eq(y[splits[1]], y_valid)\n",
    "test_type(X, X_train)\n",
    "test_type(y, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def check_data(X, y=None, splits=None, show_plot=True):\n",
    "    try: X_is_nan = np.isnan(X).sum()\n",
    "    except: X_is_nan = 'couldn not be checked'\n",
    "    if X.ndim == 3:\n",
    "        shape = f'[{X.shape[0]} samples x {X.shape[1]} features x {X.shape[-1]} timesteps]'\n",
    "        print(f'X      - shape: {shape}  type: {cls_name(X)}  dtype:{X.dtype}  isnan: {X_is_nan}')\n",
    "    else:\n",
    "        print(f'X      - shape: {X.shape}  type: {cls_name(X)}  dtype:{X.dtype}  isnan: {X_is_nan}')\n",
    "    if not isinstance(X, np.ndarray): warnings.warn('X must be a np.ndarray')\n",
    "    if X_is_nan: \n",
    "        warnings.warn('X must not contain nan values')\n",
    "    if y is not None:\n",
    "        y_shape = y.shape\n",
    "        y = y.ravel()\n",
    "        if isinstance(y[0], str):\n",
    "            n_classes = f'{len(np.unique(y))} ({len(y)//len(np.unique(y))} samples per class) {L(np.unique(y).tolist())}'\n",
    "            y_is_nan = 'nan' in [c.lower() for c in np.unique(y)]\n",
    "            print(f'y      - shape: {y_shape}  type: {cls_name(y)}  dtype:{y.dtype}  n_classes: {n_classes}  isnan: {y_is_nan}')\n",
    "        else:\n",
    "            y_is_nan = np.isnan(y).sum()\n",
    "            print(f'y      - shape: {y_shape}  type: {cls_name(y)}  dtype:{y.dtype}  isnan: {y_is_nan}')\n",
    "        if not isinstance(y, np.ndarray): warnings.warn('y must be a np.ndarray')\n",
    "        if y_is_nan: \n",
    "            warnings.warn('y must not contain nan values')\n",
    "    if splits is not None:\n",
    "        _splits = get_splits_len(splits)\n",
    "        overlap = check_splits_overlap(splits)\n",
    "        print(f'splits - n_splits: {len(_splits)} shape: {_splits}  overlap: {overlap}')\n",
    "        if show_plot: plot_splits(splits)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: [884 samples x 1 features x 136 timesteps]  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:<U1  n_classes: 2 (442 samples per class) ['1', '2']  isnan: False\n",
      "splits - n_splits: 2 shape: [23, 861]  overlap: False\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x36 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: (884, 136)  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:<U1  n_classes: 2 (442 samples per class) ['1', '2']  isnan: False\n",
      "splits - n_splits: 2 shape: [23, 861]  overlap: False\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABAYAAABKCAYAAAAoj1bdAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAARCklEQVR4nO3dfZRU9X3H8c9nd5GHoOjCCsJqSMDw4IYF14CmBBFTqkaTGsUn0CQNsceT0ySaRpI2Rw3iadqT05jWtCfxIdCaUC2gVY+t2ojgwwlRiBuJgCDFgGHdJbsrIkF22G//mLtxsu4TZHbvsPN+nbOHuff+5ne/M98zc5nv/H6/cUQIAAAAAAAUp5K0AwAAAAAAAOmhMAAAAAAAQBGjMAAAAAAAQBGjMAAAAAAAQBGjMAAAAAAAQBGjMAAAAAAAQBGjMAAAOGrZfsr2wuT2fNuP/xF9jbUdtsuS7f+2/Zk8xfkx21tytnfY/ng++k76+5Xt2fnqDwAAFBcKAwCAVNmeafs522/abrT9rO2PHG4/EfHjiJib02/YHn+kcUXE+RGxrLt2PTlPRDwdEROONJZ251tqe0m7/k+LiKfy0T8AACg+ZWkHAAAoXraPk/SIpOsk3S/pGEkfk/ROmnHlk+2yiMikHQcAAEBnGDEAAEjThyQpIpZHxKGI+F1EPB4Rv5Qk259NRhDckYwo2Gz73I46Sto+k9xem+yutb3P9uUdtC+1/R3be2xvl/SJdsdzpymMt70miWGP7fs6O4/t2bZ32V5ku07Sj9r2tQvhI7Zftt1k+0e2B7V/HDmxRBLDtZLmS7oxOd/DyfHfT02wPdD27bZ/k/zdbntgcqwttq/arre92/bnus0SAADo1ygMAADS9IqkQ7aX2T7f9gkdtJkh6VVJIyTdLGmV7fKuOo2IWcnN6ogYGhH3ddDsC5IulDRN0hmSLu2iy1slPS7pBEmVkv65m/OMklQu6f2Sru2kz/mS/kzSOGULJN/s6jEl5/uhpB9L+ofkfBd10OxvJZ0paaqkaknT2/U9StIwSWMkfV7S9zt53gEAQJGgMAAASE1E7JU0U1JIulNSg+2HbI/MaVYv6faIaEk+eG9Ru2/3j9BlSb87I6JR0t910bZF2Q/5oyPiQEQ800VbSWqVdHNEvBMRv+ukzR05575N0pWH+wA6MV/S4oioj4gGSd+SdHXO8ZbkeEtEPCppn6S8rH8AAACOThQGAACpiohNEfHZiKiUVCVptKTbc5q8HhGRs/1a0uaPNVrSznb9duZGSZb08+QXAP6im74bIuJAN23anzsfj0lJP7mPpX3fv2235sF+SUPzdG4AAHAUojAAACgYEbFZ0lJlCwRtxth2zvYpkn6Th9PtlnRyu347i6suIr4QEaMl/aWkf+nmlwiii2Nt2p+77TG9LWlI2wHbow6z798oO7qho74BAADeg8IAACA1ticmC+FVJtsnKzuk/mc5zU6U9CXbA2zPkzRJ0qM96P4NSR/s4vj9Sb+VyRz7r3cR57y2GCU1KfvhvLWH5+nMF5Nzlyu7LkDb+gS1kk6zPTVZkPCWdvfr7nzLJX3TdoXtEZJuknTvEcQHAACKBIUBAECa3lJ2ccF1tt9WtiCwUdJXc9qsk3SqpD3KzsW/NCJ+24O+b5G0zHaz7cs6OH6npMeU/SC+QdKqLvr6SBLjPkkPSfpyRGzv4Xk68xNlFzTcruziikskKSJekbRY0v9K2iqp/XoGd0uanJzvwQ76XSLpBUm/lPRS8tiWHEZcAACgyPgPp20CAFA4bH9W0sKImJl2LAAAAP0VIwYAAAAAAChiFAYAAAAAAChiTCUAAAAAAKCIMWIAAAAAAIAiRmEAAAAAAIAiVtYbndojQhqb936HTNqU9z4BAAAAAD23f9P+PRFRkXYcyJ9eKQxkiwIv5L3XiffW5L1PAAAAAEDPbajZ8FraMSC/mEoAAAAAAEARozAAAAAAAEARozAAAAAAAEAR66U1BgAAAAAAKFzr168/says7C5JVerfX5q3StqYyWQW1tTU1HfUgMIAAAAAAKDolJWV3TVq1KhJFRUVTSUlJZF2PL2ltbXVDQ0Nk+vq6u6S9MmO2vTnqggAAAAAAJ2pqqio2NufiwKSVFJSEhUVFW8qOzKi4zZ9GA8AAAAAAIWipL8XBdokj7PTz/9MJQAAAAAAoI/V1dWVzp49e4Ik7dmzZ0BJSUmUl5dnJOnFF1/cNGjQoE6LFmvXrh1yzz33DF+6dOnOfMTSbWHA9j2SLpRUHxGdDj0AAAAAAOBoZasmn/1FaH1Xx0eNGnVo8+bNL0vSDTfcMHro0KGHFi9e/Ebb8ZaWFg0YMKDD+86aNWv/rFmz9ucr1p5MJVgq6bx8nRAAAAAAALzXJZdcMvaqq646ZcqUKROvu+66ytWrVw+ZOnXqxEmTJk2eNm3axNra2oGS9Mgjjxx7zjnnjJeyRYV58+aNnT59+oTKysoPL1my5MTDPW+3IwYiYq3tsYf9iAAAAAAAwGHZvXv3MRs2bNhcVlamxsbGkueff37zgAED9OCDDx574403Vj722GOvtr/Ptm3bBj333HNbmpubSydNmlT1ta99rWHgwIE9Xj8hb2sM2L5W0rXZrVPy1S0AAAAAAEXj05/+dFNZWfajemNjY+nll1/+gR07dgyyHS0tLe7oPnPnzm0ePHhwDB48OFNeXt6ya9eusnHjxrX09Jx5+1WCiPhhRJwREWdIFfnqFgAAAACAojF06NDWttuLFi0ac/bZZ7+1devWXz388MPbDh482OFn+NzRAaWlpcpkMh0WEDrDzxUCAAAAAFCA9u7dW1pZWXlQkn7wgx+M6K3zUBgAAAAAAKAALVq0qO6WW26pnDRp0uRMJtNr53FE1+sR2F4uabakEZLekHRzRNzd9X3OCOmFfMX4e6evz+uvRwAAAAAADtOGmg3rs1PIj261tbU7qqur96QdR1+pra0dUV1dPbajYz35VYIr8x4RAAAAAAAoCEwlAAAAAACgiFEYAAAAAACgiFEYAAAAAACgiFEYAAAAAACgiFEYAAAAAACgiFEYAAAAAACgj82YMeNDK1euPC533+LFi0+cP3/+KR21nz59+oS1a9cOkaSzzz57/J49e0rbt7nhhhtG33TTTSMPN5Zuf64QAAAAAID+rmZDTU0++1t/+vr1XR2fN29e4/Lly8svueSSvW37Vq5cWf7tb397V3d9r1mzZls+YmzDiAEAAAAAAPrY1Vdf3fTkk08OO3DggCVpy5Ytx9TX1w+49957y6uqqiaNHz/+tOuvv350R/cdM2bMh3fv3l0mSYsWLRo1duzYqpqamglbt24deCSx9NKIgfX7JG/Jd68b8lq/KTojJO1JOwj8AXJSeMhJ4SEnhYecFB5yUnjISeEhJ/n1/rQD6A9Gjhx5qLq6+u0VK1YMW7BgQfOyZcvKL7rooqZbb71198iRIw9lMhl99KMfnbBu3brBM2bM+F1HfTz99NNDHnjggfKXXnrp5ZaWFk2dOnXytGnT9h9uLL01lWBLRJzRS33jCNh+gZwUFnJSeMhJ4SEnhYecFB5yUnjISeEhJyhUl112WeN99913woIFC5pXrVpVfuedd+5YtmxZ+dKlS0dkMhk3NDQMqK2tHdRZYWD16tVDL7jgguZjjz22VZLmzp3bfCRxMJUAAAAAAIAUXHXVVc3PPvvscc8888yQAwcOlFRUVGTuuOOOkWvWrHnllVdeeXnOnDlvHjhwoNc/t1MYAAAAAAAgBcOGDWs966yz3lq4cOHYiy++uLGpqal08ODBreXl5Yd27txZ9tRTTw3r6v5z5szZ9+ijjx6/b98+NzU1lTzxxBPHH0kcvTWV4Ie91C+OHDkpPOSk8JCTwkNOCg85KTzkpPCQk8JDTlCwrrjiisZrrrlm3PLly7dPmzbtQFVV1f5x48ZVnXTSSQdramr2dXXfmTNn7r/44osbq6qqThs+fHjLlClT3j6SGBwRRxY9AAAAAABHqdra2h3V1dVFsyhlbW3tiOrq6rEdHWMqAQAAAAAARSyvhQHb59neYnub7a/ns290zvY9tuttb8zZV277Cdtbk39PSPbb9j8lOfql7dPTi7z/sn2y7dW2X7b9K9tfTvaTl5TYHmT757Zrk5x8K9n/Advrkuf+PtvHJPsHJtvbkuNjU30A/ZjtUtu/sP1Isk1OUmR7h+2XbL9o+4VkH+9dKbJ9vO0Vtjfb3mT7LHKSHtsTktdH299e218hJ+myfX1yfd9oe3ly3ed6AvRQ3goDtkslfV/S+ZImS7rS9uR89Y8uLZV0Xrt9X5f004g4VdJPk20pm59Tk79rJf1rH8VYbDKSvhoRkyWdKemLyeuBvKTnHUlzIqJa0lRJ59k+U9LfS/puRIyX1CTp80n7z0tqSvZ/N2mH3vFlSZtytslJ+s6JiKk5P+3Fe1e6vifpfyJioqRqZV8v5CQlEbEleX1MlVQjab+kB0ROUmN7jKQvSTojIqoklUq6QlxPgB7L54iB6ZK2RcT2iDgo6T8kfSqP/aMTEbFWUmO73Z+StCy5vUzSn+fs/7fI+pmk422f1CeBFpGI2B0RG5Lbbyn7n7gxIi+pSZ7btsVbBiR/IWmOpBXJ/vY5acvVCknn2nbfRFs8bFdK+oSku5Jti5wUIt67UmJ7mKRZku6WpIg4GBHNIieF4lxJr0bEayInaSuTNNh2maQhknaL6wm619ra2loUuU8eZ2tnx/NZGBgjaWfO9q5kH9IxMiJ2J7frJI1MbpOnPpYMT5smaZ3IS6qSIesvSqqX9ISkVyU1R0QmaZL7vP8+J8nxNyUN79OAi8Ptkm7Uuxeq4SInaQtJj9teb/vaZB/vXen5gKQGST9KptzcZft9IieF4gpJy5Pb5CQlEfG6pO9I+rWyBYE3Ja0X1xN0b2NDQ8Ow/l4caG1tdUNDwzBJGztr01s/V4gCEhFhm5+fSIHtoZJWSvpKROzNLUaTl74XEYckTbV9vLLDPiemG1Fxs32hpPqIWG97dsrh4F0zI+J12ydKesL25tyDvHf1uTJJp0v6q4hYZ/t7eneIuiRykpZkvvonJX2j/TFy0reS9Rw+pWwhrVnSf+q902yB98hkMgvr6uruqqurq1L/Xpi/VdLGTCazsLMG+SwMvC7p5JztymQf0vGG7ZMiYncyXK0+2U+e+ojtAcoWBX4cEauS3eSlAEREs+3Vks5SdkhnWfKNQe7z3paTXcmwxGGSfptKwP3Xn0j6pO0LJA2SdJyyc6nJSYqSb94UEfW2H1B2qiDvXenZJWlXRKxLtlcoWxggJ+k7X9KGiHgj2SYn6fm4pP+LiAZJsr1K2WsM1xN0qaampl7ZAl/Ry2dV5HlJpyarfx6j7NCqh/LYPw7PQ5I+k9z+jKT/ytl/TbJC7pmS3swZ9oY8Seap3S1pU0T8Y84h8pIS2xXJSAHZHizpT5Vd+2G1pEuTZu1z0parSyU9GRF8+5NHEfGNiKiMiLHKXjOejIj5Iiepsf0+28e23ZY0V9lhh7x3pSQi6iTttD0h2XWupJdFTgrBlXp3GoFETtL0a0ln2h6S/B+s7XXC9QToIefzNZB863O7siuB3hMRt+Wtc3TK9nJJsyWNkPSGpJslPSjpfkmnSHpN0mUR0Zi8Wd6h7PCq/ZI+FxEvpBB2v2Z7pqSnJb2kd+dO/42y6wyQlxTYnqLsQkOlyhZF74+IxbY/qOxiqeWSfiFpQUS8Y3uQpH9Xdn2IRklXRMT2dKLv/5KpBH8dEReSk/Qkz/0DyWaZpJ9ExG22h4v3rtTYnqrsAp3HSNou6XNK3sdETlKRFM5+LemDEfFmso/XSYqc/Rniy5X9ZahfSFqo7FoCXE+AHshrYQAAAAAAABxd+vMCCwAAAAAAoBsUBgAAAAAAKGIUBgAAAAAAKGIUBgAAAAAAKGIUBgAAAAAAKGIUBgAAAAAAKGIUBgAAAAAAKGIUBgAAAAAAKGL/D98/kjMjFvsPAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 1152x36 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: [884 samples x 1 features x 136 timesteps]  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:float32  isnan: 0\n",
      "splits - n_splits: 2 shape: [23, 861]  overlap: False\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x36 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: (884, 136)  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:float32  isnan: 10\n",
      "splits - n_splits: 2 shape: [23, 861]  overlap: False\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/nacho/opt/anaconda3/envs/py36/lib/python3.6/site-packages/ipykernel_launcher.py:25: UserWarning: y must not contain nan values\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x36 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x108 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: [884 samples x 1 features x 136 timesteps]  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:<U1  n_classes: 2 (442 samples per class) ['1', '2']  isnan: False\n",
      "splits - n_splits: 3 shape: [[589, 295], [589, 295], [590, 294]]  overlap: [False, False, False]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x108 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: (884, 136)  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:<U1  n_classes: 2 (442 samples per class) ['1', '2']  isnan: False\n",
      "splits - n_splits: 3 shape: [[589, 295], [589, 295], [590, 294]]  overlap: [False, False, False]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x108 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X      - shape: (884, 136)  type: ndarray  dtype:float32  isnan: 0\n",
      "y      - shape: (884,)  type: ndarray  dtype:<U1  n_classes: 3 (294 samples per class) ['1', '2', 'n']  isnan: False\n",
      "splits - n_splits: 3 shape: [[589, 295], [589, 295], [590, 294]]  overlap: [False, False, False]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1152x108 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "dsid = 'ECGFiveDays'\n",
    "X, y, splits = get_UCR_data(dsid, split_data=False, on_disk=False, force_download=False)\n",
    "check_data(X, y, splits)\n",
    "check_data(X[:, 0], y, splits)\n",
    "y = y.astype(np.float32)\n",
    "check_data(X, y, splits)\n",
    "y[:10] = np.nan\n",
    "check_data(X[:, 0], y, splits)\n",
    "X, y, splits = get_UCR_data(dsid, split_data=False, on_disk=False, force_download=False)\n",
    "splits = get_splits(y, 3)\n",
    "check_data(X, y, splits)\n",
    "check_data(X[:, 0], y, splits)\n",
    "y[:5]= np.nan\n",
    "check_data(X[:, 0], y, splits)\n",
    "X, y, splits = get_UCR_data(dsid, split_data=False, on_disk=False, force_download=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "# This code comes from https://github.com/ChangWeiTan/TSRegression. As of Jan 16th, 2021 there's no pip install available.\n",
    "\n",
    "# The following code is adapted from the python package sktime to read .ts file.\n",
    "class _TsFileParseException(Exception):\n",
    "    \"\"\"\n",
    "    Should be raised when parsing a .ts file and the format is incorrect.\n",
    "    \"\"\"\n",
    "    pass\n",
    "\n",
    "def _load_from_tsfile_to_dataframe2(full_file_path_and_name, return_separate_X_and_y=True, replace_missing_vals_with='NaN'):\n",
    "    \"\"\"Loads data from a .ts file into a Pandas DataFrame.\n",
    "    Parameters\n",
    "    ----------\n",
    "    full_file_path_and_name: str\n",
    "        The full pathname of the .ts file to read.\n",
    "    return_separate_X_and_y: bool\n",
    "        true if X and Y values should be returned as separate Data Frames (X) and a numpy array (y), false otherwise.\n",
    "        This is only relevant for data that\n",
    "    replace_missing_vals_with: str\n",
    "       The value that missing values in the text file should be replaced with prior to parsing.\n",
    "    Returns\n",
    "    -------\n",
    "    DataFrame, ndarray\n",
    "        If return_separate_X_and_y then a tuple containing a DataFrame and a numpy array containing the relevant time-series and corresponding class values.\n",
    "    DataFrame\n",
    "        If not return_separate_X_and_y then a single DataFrame containing all time-series and (if relevant) a column \"class_vals\" the associated class values.\n",
    "    \"\"\"\n",
    "\n",
    "    # Initialize flags and variables used when parsing the file\n",
    "    metadata_started = False\n",
    "    data_started = False\n",
    "\n",
    "    has_problem_name_tag = False\n",
    "    has_timestamps_tag = False\n",
    "    has_univariate_tag = False\n",
    "    has_class_labels_tag = False\n",
    "    has_target_labels_tag = False\n",
    "    has_data_tag = False\n",
    "\n",
    "    previous_timestamp_was_float = None\n",
    "    previous_timestamp_was_int = None\n",
    "    previous_timestamp_was_timestamp = None\n",
    "    num_dimensions = None\n",
    "    is_first_case = True\n",
    "    instance_list = []\n",
    "    class_val_list = []\n",
    "    line_num = 0\n",
    "\n",
    "    # Parse the file\n",
    "    # print(full_file_path_and_name)\n",
    "    with open(full_file_path_and_name, 'r', encoding='utf-8') as file:\n",
    "        for line in tqdm(file):\n",
    "            # print(\".\", end='')\n",
    "            # Strip white space from start/end of line and change to lowercase for use below\n",
    "            line = line.strip().lower()\n",
    "            # Empty lines are valid at any point in a file\n",
    "            if line:\n",
    "                # Check if this line contains metadata\n",
    "                # Please note that even though metadata is stored in this function it is not currently published externally\n",
    "                if line.startswith(\"@problemname\"):\n",
    "                    # Check that the data has not started\n",
    "                    if data_started:\n",
    "                        raise _TsFileParseException(\"metadata must come before data\")\n",
    "                    # Check that the associated value is valid\n",
    "                    tokens = line.split(' ')\n",
    "                    token_len = len(tokens)\n",
    "\n",
    "                    if token_len == 1:\n",
    "                        raise _TsFileParseException(\"problemname tag requires an associated value\")\n",
    "\n",
    "                    problem_name = line[len(\"@problemname\") + 1:]\n",
    "                    has_problem_name_tag = True\n",
    "                    metadata_started = True\n",
    "                elif line.startswith(\"@timestamps\"):\n",
    "                    # Check that the data has not started\n",
    "                    if data_started:\n",
    "                        raise _TsFileParseException(\"metadata must come before data\")\n",
    "\n",
    "                    # Check that the associated value is valid\n",
    "                    tokens = line.split(' ')\n",
    "                    token_len = len(tokens)\n",
    "\n",
    "                    if token_len != 2:\n",
    "                        raise _TsFileParseException(\"timestamps tag requires an associated Boolean value\")\n",
    "                    elif tokens[1] == \"true\":\n",
    "                        timestamps = True\n",
    "                    elif tokens[1] == \"false\":\n",
    "                        timestamps = False\n",
    "                    else:\n",
    "                        raise _TsFileParseException(\"invalid timestamps value\")\n",
    "                    has_timestamps_tag = True\n",
    "                    metadata_started = True\n",
    "                elif line.startswith(\"@univariate\"):\n",
    "                    # Check that the data has not started\n",
    "                    if data_started:\n",
    "                        raise _TsFileParseException(\"metadata must come before data\")\n",
    "\n",
    "                    # Check that the associated value is valid\n",
    "                    tokens = line.split(' ')\n",
    "                    token_len = len(tokens)\n",
    "                    if token_len != 2:\n",
    "                        raise _TsFileParseException(\"univariate tag requires an associated Boolean value\")\n",
    "                    elif tokens[1] == \"true\":\n",
    "                        univariate = True\n",
    "                    elif tokens[1] == \"false\":\n",
    "                        univariate = False\n",
    "                    else:\n",
    "                        raise _TsFileParseException(\"invalid univariate value\")\n",
    "\n",
    "                    has_univariate_tag = True\n",
    "                    metadata_started = True\n",
    "                elif line.startswith(\"@classlabel\"):\n",
    "                    # Check that the data has not started\n",
    "                    if data_started:\n",
    "                        raise _TsFileParseException(\"metadata must come before data\")\n",
    "\n",
    "                    # Check that the associated value is valid\n",
    "                    tokens = line.split(' ')\n",
    "                    token_len = len(tokens)\n",
    "\n",
    "                    if token_len == 1:\n",
    "                        raise _TsFileParseException(\"classlabel tag requires an associated Boolean value\")\n",
    "\n",
    "                    if tokens[1] == \"true\":\n",
    "                        class_labels = True\n",
    "                    elif tokens[1] == \"false\":\n",
    "                        class_labels = False\n",
    "                    else:\n",
    "                        raise _TsFileParseException(\"invalid classLabel value\")\n",
    "\n",
    "                    # Check if we have any associated class values\n",
    "                    if token_len == 2 and class_labels:\n",
    "                        raise _TsFileParseException(\"if the classlabel tag is true then class values must be supplied\")\n",
    "\n",
    "                    has_class_labels_tag = True\n",
    "                    class_label_list = [token.strip() for token in tokens[2:]]\n",
    "                    metadata_started = True\n",
    "                elif line.startswith(\"@targetlabel\"):\n",
    "                    # Check that the data has not started\n",
    "                    if data_started:\n",
    "                        raise _TsFileParseException(\"metadata must come before data\")\n",
    "\n",
    "                    # Check that the associated value is valid\n",
    "                    tokens = line.split(' ')\n",
    "                    token_len = len(tokens)\n",
    "\n",
    "                    if token_len == 1:\n",
    "                        raise _TsFileParseException(\"targetlabel tag requires an associated Boolean value\")\n",
    "\n",
    "                    if tokens[1] == \"true\":\n",
    "                        target_labels = True\n",
    "                    elif tokens[1] == \"false\":\n",
    "                        target_labels = False\n",
    "                    else:\n",
    "                        raise _TsFileParseException(\"invalid targetLabel value\")\n",
    "\n",
    "                    has_target_labels_tag = True\n",
    "                    class_val_list = []\n",
    "                    metadata_started = True\n",
    "                # Check if this line contains the start of data\n",
    "                elif line.startswith(\"@data\"):\n",
    "                    if line != \"@data\":\n",
    "                        raise _TsFileParseException(\"data tag should not have an associated value\")\n",
    "\n",
    "                    if data_started and not metadata_started:\n",
    "                        raise _TsFileParseException(\"metadata must come before data\")\n",
    "                    else:\n",
    "                        has_data_tag = True\n",
    "                        data_started = True\n",
    "                # If the 'data tag has been found then metadata has been parsed and data can be loaded\n",
    "                elif data_started:\n",
    "                    # Check that a full set of metadata has been provided\n",
    "                    incomplete_regression_meta_data = not has_problem_name_tag or not has_timestamps_tag or not has_univariate_tag or not has_target_labels_tag or not has_data_tag\n",
    "                    incomplete_classification_meta_data = not has_problem_name_tag or not has_timestamps_tag or not has_univariate_tag or not has_class_labels_tag or not has_data_tag\n",
    "                    if incomplete_regression_meta_data and incomplete_classification_meta_data:\n",
    "                        raise _TsFileParseException(\"a full set of metadata has not been provided before the data\")\n",
    "\n",
    "                    # Replace any missing values with the value specified\n",
    "                    line = line.replace(\"?\", replace_missing_vals_with)\n",
    "\n",
    "                    # Check if we dealing with data that has timestamps\n",
    "                    if timestamps:\n",
    "                        # We're dealing with timestamps so cannot just split line on ':' as timestamps may contain one\n",
    "                        has_another_value = False\n",
    "                        has_another_dimension = False\n",
    "\n",
    "                        timestamps_for_dimension = []\n",
    "                        values_for_dimension = []\n",
    "\n",
    "                        this_line_num_dimensions = 0\n",
    "                        line_len = len(line)\n",
    "                        char_num = 0\n",
    "\n",
    "                        while char_num < line_len:\n",
    "                            # Move through any spaces\n",
    "                            while char_num < line_len and str.isspace(line[char_num]):\n",
    "                                char_num += 1\n",
    "\n",
    "                            # See if there is any more data to read in or if we should validate that read thus far\n",
    "\n",
    "                            if char_num < line_len:\n",
    "\n",
    "                                # See if we have an empty dimension (i.e. no values)\n",
    "                                if line[char_num] == \":\":\n",
    "                                    if len(instance_list) < (this_line_num_dimensions + 1):\n",
    "                                        instance_list.append([])\n",
    "\n",
    "                                    instance_list[this_line_num_dimensions].append(pd.Series())\n",
    "                                    this_line_num_dimensions += 1\n",
    "\n",
    "                                    has_another_value = False\n",
    "                                    has_another_dimension = True\n",
    "\n",
    "                                    timestamps_for_dimension = []\n",
    "                                    values_for_dimension = []\n",
    "\n",
    "                                    char_num += 1\n",
    "                                else:\n",
    "                                    # Check if we have reached a class label\n",
    "                                    if line[char_num] != \"(\" and target_labels:\n",
    "                                        class_val = line[char_num:].strip()\n",
    "\n",
    "                                        # if class_val not in class_val_list:\n",
    "                                        #     raise _TsFileParseException(\n",
    "                                        #         \"the class value '\" + class_val + \"' on line \" + str(\n",
    "                                        #             line_num + 1) + \" is not valid\")\n",
    "\n",
    "                                        class_val_list.append(float(class_val))\n",
    "                                        char_num = line_len\n",
    "\n",
    "                                        has_another_value = False\n",
    "                                        has_another_dimension = False\n",
    "\n",
    "                                        timestamps_for_dimension = []\n",
    "                                        values_for_dimension = []\n",
    "\n",
    "                                    else:\n",
    "\n",
    "                                        # Read in the data contained within the next tuple\n",
    "\n",
    "                                        if line[char_num] != \"(\" and not target_labels:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" does not start with a '('\")\n",
    "\n",
    "                                        char_num += 1\n",
    "                                        tuple_data = \"\"\n",
    "\n",
    "                                        while char_num < line_len and line[char_num] != \")\":\n",
    "                                            tuple_data += line[char_num]\n",
    "                                            char_num += 1\n",
    "\n",
    "                                        if char_num >= line_len or line[char_num] != \")\":\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" does not end with a ')'\")\n",
    "\n",
    "                                        # Read in any spaces immediately after the current tuple\n",
    "\n",
    "                                        char_num += 1\n",
    "\n",
    "                                        while char_num < line_len and str.isspace(line[char_num]):\n",
    "                                            char_num += 1\n",
    "\n",
    "                                        # Check if there is another value or dimension to process after this tuple\n",
    "\n",
    "                                        if char_num >= line_len:\n",
    "                                            has_another_value = False\n",
    "                                            has_another_dimension = False\n",
    "\n",
    "                                        elif line[char_num] == \",\":\n",
    "                                            has_another_value = True\n",
    "                                            has_another_dimension = False\n",
    "\n",
    "                                        elif line[char_num] == \":\":\n",
    "                                            has_another_value = False\n",
    "                                            has_another_dimension = True\n",
    "\n",
    "                                        char_num += 1\n",
    "\n",
    "                                        # Get the numeric value for the tuple by reading from the end of the tuple data backwards to the last comma\n",
    "\n",
    "                                        last_comma_index = tuple_data.rfind(',')\n",
    "\n",
    "                                        if last_comma_index == -1:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" contains a tuple that has no comma inside of it\")\n",
    "\n",
    "                                        try:\n",
    "                                            value = tuple_data[last_comma_index + 1:]\n",
    "                                            value = float(value)\n",
    "\n",
    "                                        except ValueError:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" contains a tuple that does not have a valid numeric value\")\n",
    "\n",
    "                                        # Check the type of timestamp that we have\n",
    "\n",
    "                                        timestamp = tuple_data[0: last_comma_index]\n",
    "\n",
    "                                        try:\n",
    "                                            timestamp = int(timestamp)\n",
    "                                            timestamp_is_int = True\n",
    "                                            timestamp_is_timestamp = False\n",
    "                                        except ValueError:\n",
    "                                            timestamp_is_int = False\n",
    "\n",
    "                                        if not timestamp_is_int:\n",
    "                                            try:\n",
    "                                                timestamp = float(timestamp)\n",
    "                                                timestamp_is_float = True\n",
    "                                                timestamp_is_timestamp = False\n",
    "                                            except ValueError:\n",
    "                                                timestamp_is_float = False\n",
    "\n",
    "                                        if not timestamp_is_int and not timestamp_is_float:\n",
    "                                            try:\n",
    "                                                timestamp = timestamp.strip()\n",
    "                                                timestamp_is_timestamp = True\n",
    "                                            except ValueError:\n",
    "                                                timestamp_is_timestamp = False\n",
    "\n",
    "                                        # Make sure that the timestamps in the file (not just this dimension or case) are consistent\n",
    "\n",
    "                                        if not timestamp_is_timestamp and not timestamp_is_int and not timestamp_is_float:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" contains a tuple that has an invalid timestamp '\" + timestamp + \"'\")\n",
    "\n",
    "                                        if previous_timestamp_was_float is not None and previous_timestamp_was_float and not timestamp_is_float:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" contains tuples where the timestamp format is inconsistent\")\n",
    "\n",
    "                                        if previous_timestamp_was_int is not None and previous_timestamp_was_int and not timestamp_is_int:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" contains tuples where the timestamp format is inconsistent\")\n",
    "\n",
    "                                        if previous_timestamp_was_timestamp is not None and previous_timestamp_was_timestamp and not timestamp_is_timestamp:\n",
    "                                            raise _TsFileParseException(\n",
    "                                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                                    line_num + 1) + \" contains tuples where the timestamp format is inconsistent\")\n",
    "\n",
    "                                        # Store the values\n",
    "\n",
    "                                        timestamps_for_dimension += [timestamp]\n",
    "                                        values_for_dimension += [value]\n",
    "\n",
    "                                        #  If this was our first tuple then we store the type of timestamp we had\n",
    "\n",
    "                                        if previous_timestamp_was_timestamp is None and timestamp_is_timestamp:\n",
    "                                            previous_timestamp_was_timestamp = True\n",
    "                                            previous_timestamp_was_int = False\n",
    "                                            previous_timestamp_was_float = False\n",
    "\n",
    "                                        if previous_timestamp_was_int is None and timestamp_is_int:\n",
    "                                            previous_timestamp_was_timestamp = False\n",
    "                                            previous_timestamp_was_int = True\n",
    "                                            previous_timestamp_was_float = False\n",
    "\n",
    "                                        if previous_timestamp_was_float is None and timestamp_is_float:\n",
    "                                            previous_timestamp_was_timestamp = False\n",
    "                                            previous_timestamp_was_int = False\n",
    "                                            previous_timestamp_was_float = True\n",
    "\n",
    "                                        # See if we should add the data for this dimension\n",
    "\n",
    "                                        if not has_another_value:\n",
    "                                            if len(instance_list) < (this_line_num_dimensions + 1):\n",
    "                                                instance_list.append([])\n",
    "\n",
    "                                            if timestamp_is_timestamp:\n",
    "                                                timestamps_for_dimension = pd.DatetimeIndex(timestamps_for_dimension)\n",
    "\n",
    "                                            instance_list[this_line_num_dimensions].append(\n",
    "                                                pd.Series(index=timestamps_for_dimension, data=values_for_dimension))\n",
    "                                            this_line_num_dimensions += 1\n",
    "\n",
    "                                            timestamps_for_dimension = []\n",
    "                                            values_for_dimension = []\n",
    "\n",
    "                            elif has_another_value:\n",
    "                                raise _TsFileParseException(\n",
    "                                    \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                        line_num + 1) + \" ends with a ',' that is not followed by another tuple\")\n",
    "\n",
    "                            elif has_another_dimension and target_labels:\n",
    "                                raise _TsFileParseException(\n",
    "                                    \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                        line_num + 1) + \" ends with a ':' while it should list a class value\")\n",
    "\n",
    "                            elif has_another_dimension and not target_labels:\n",
    "                                if len(instance_list) < (this_line_num_dimensions + 1):\n",
    "                                    instance_list.append([])\n",
    "\n",
    "                                instance_list[this_line_num_dimensions].append(pd.Series(dtype=np.float32))\n",
    "                                this_line_num_dimensions += 1\n",
    "                                num_dimensions = this_line_num_dimensions\n",
    "\n",
    "                            # If this is the 1st line of data we have seen then note the dimensions\n",
    "\n",
    "                            if not has_another_value and not has_another_dimension:\n",
    "                                if num_dimensions is None:\n",
    "                                    num_dimensions = this_line_num_dimensions\n",
    "\n",
    "                                if num_dimensions != this_line_num_dimensions:\n",
    "                                    raise _TsFileParseException(\"line \" + str(\n",
    "                                        line_num + 1) + \" does not have the same number of dimensions as the previous line of data\")\n",
    "\n",
    "                        # Check that we are not expecting some more data, and if not, store that processed above\n",
    "\n",
    "                        if has_another_value:\n",
    "                            raise _TsFileParseException(\n",
    "                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                    line_num + 1) + \" ends with a ',' that is not followed by another tuple\")\n",
    "\n",
    "                        elif has_another_dimension and target_labels:\n",
    "                            raise _TsFileParseException(\n",
    "                                \"dimension \" + str(this_line_num_dimensions + 1) + \" on line \" + str(\n",
    "                                    line_num + 1) + \" ends with a ':' while it should list a class value\")\n",
    "\n",
    "                        elif has_another_dimension and not target_labels:\n",
    "                            if len(instance_list) < (this_line_num_dimensions + 1):\n",
    "                                instance_list.append([])\n",
    "\n",
    "                            instance_list[this_line_num_dimensions].append(pd.Series())\n",
    "                            this_line_num_dimensions += 1\n",
    "                            num_dimensions = this_line_num_dimensions\n",
    "\n",
    "                        # If this is the 1st line of data we have seen then note the dimensions\n",
    "\n",
    "                        if not has_another_value and num_dimensions != this_line_num_dimensions:\n",
    "                            raise _TsFileParseException(\"line \" + str(\n",
    "                                line_num + 1) + \" does not have the same number of dimensions as the previous line of data\")\n",
    "\n",
    "                        # Check if we should have class values, and if so that they are contained in those listed in the metadata\n",
    "\n",
    "                        if target_labels and len(class_val_list) == 0:\n",
    "                            raise _TsFileParseException(\"the cases have no associated class values\")\n",
    "                    else:\n",
    "                        dimensions = line.split(\":\")\n",
    "                        # If first row then note the number of dimensions (that must be the same for all cases)\n",
    "                        if is_first_case:\n",
    "                            num_dimensions = len(dimensions)\n",
    "\n",
    "                            if target_labels:\n",
    "                                num_dimensions -= 1\n",
    "\n",
    "                            for dim in range(0, num_dimensions):\n",
    "                                instance_list.append([])\n",
    "                            is_first_case = False\n",
    "\n",
    "                        # See how many dimensions that the case whose data in represented in this line has\n",
    "                        this_line_num_dimensions = len(dimensions)\n",
    "\n",
    "                        if target_labels:\n",
    "                            this_line_num_dimensions -= 1\n",
    "\n",
    "                        # All dimensions should be included for all series, even if they are empty\n",
    "                        if this_line_num_dimensions != num_dimensions:\n",
    "                            raise _TsFileParseException(\"inconsistent number of dimensions. Expecting \" + str(\n",
    "                                num_dimensions) + \" but have read \" + str(this_line_num_dimensions))\n",
    "\n",
    "                        # Process the data for each dimension\n",
    "                        for dim in range(0, num_dimensions):\n",
    "                            dimension = dimensions[dim].strip()\n",
    "\n",
    "                            if dimension:\n",
    "                                data_series = dimension.split(\",\")\n",
    "                                data_series = [float(i) for i in data_series]\n",
    "                                instance_list[dim].append(pd.Series(data_series))\n",
    "                            else:\n",
    "                                instance_list[dim].append(pd.Series())\n",
    "\n",
    "                        if target_labels:\n",
    "                            class_val_list.append(float(dimensions[num_dimensions].strip()))\n",
    "\n",
    "            line_num += 1\n",
    "\n",
    "    # Check that the file was not empty\n",
    "    if line_num:\n",
    "        # Check that the file contained both metadata and data\n",
    "        complete_regression_meta_data = has_problem_name_tag and has_timestamps_tag and has_univariate_tag and has_target_labels_tag and has_data_tag\n",
    "        complete_classification_meta_data = has_problem_name_tag and has_timestamps_tag and has_univariate_tag and has_class_labels_tag and has_data_tag\n",
    "\n",
    "        if metadata_started and not complete_regression_meta_data and not complete_classification_meta_data:\n",
    "            raise _TsFileParseException(\"metadata incomplete\")\n",
    "        elif metadata_started and not data_started:\n",
    "            raise _TsFileParseException(\"file contained metadata but no data\")\n",
    "        elif metadata_started and data_started and len(instance_list) == 0:\n",
    "            raise _TsFileParseException(\"file contained metadata but no data\")\n",
    "\n",
    "        # Create a DataFrame from the data parsed above\n",
    "        data = pd.DataFrame(dtype=np.float32)\n",
    "\n",
    "        for dim in range(0, num_dimensions):\n",
    "            data['dim_' + str(dim)] = instance_list[dim]\n",
    "\n",
    "        # Check if we should return any associated class labels separately\n",
    "\n",
    "        if target_labels:\n",
    "            if return_separate_X_and_y:\n",
    "                return data, np.asarray(class_val_list)\n",
    "            else:\n",
    "                data['class_vals'] = pd.Series(class_val_list)\n",
    "                return data\n",
    "        else:\n",
    "            return data\n",
    "    else:\n",
    "        raise _TsFileParseException(\"empty file\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "15"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#export\n",
    "def get_Monash_regression_list():\n",
    "    return sorted([\n",
    "        \"AustraliaRainfall\", \"HouseholdPowerConsumption1\",\n",
    "        \"HouseholdPowerConsumption2\", \"BeijingPM25Quality\",\n",
    "        \"BeijingPM10Quality\", \"Covid3Month\", \"LiveFuelMoistureContent\",\n",
    "        \"FloodModeling1\", \"FloodModeling2\", \"FloodModeling3\",\n",
    "        \"AppliancesEnergy\", \"BenzeneConcentration\", \"NewsHeadlineSentiment\",\n",
    "        \"NewsTitleSentiment\", \"IEEEPPG\",  \n",
    "        #\"BIDMC32RR\", \"BIDMC32HR\", \"BIDMC32SpO2\", \"PPGDalia\" # Cannot be downloaded\n",
    "    ])\n",
    "\n",
    "Monash_regression_list = get_Monash_regression_list()\n",
    "regression_list = Monash_regression_list\n",
    "TSR_datasets = regression_datasets = regression_list\n",
    "len(Monash_regression_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def get_Monash_regression_data(dsid, path='./data/Monash', on_disk=True, mode='c', Xdtype='float32', ydtype=None, split_data=True, force_download=False, \n",
    "                               verbose=False, timeout=4):\n",
    "\n",
    "    dsid_list = [rd for rd in Monash_regression_list if rd.lower() == dsid.lower()]\n",
    "    assert len(dsid_list) > 0, f'{dsid} is not a Monash dataset'\n",
    "    dsid = dsid_list[0]\n",
    "    full_tgt_dir = Path(path)/dsid\n",
    "    pv(f'Dataset: {dsid}', verbose)\n",
    "\n",
    "    if force_download or not all([os.path.isfile(f'{path}/{dsid}/{fn}.npy') for fn in ['X_train', 'X_valid', 'y_train', 'y_valid', 'X', 'y']]):\n",
    "        if dsid == 'AppliancesEnergy': dset_id = 3902637\n",
    "        elif dsid == 'HouseholdPowerConsumption1': dset_id = 3902704\n",
    "        elif dsid == 'HouseholdPowerConsumption2': dset_id = 3902706\n",
    "        elif dsid == 'BenzeneConcentration': dset_id = 3902673\n",
    "        elif dsid == 'BeijingPM25Quality': dset_id = 3902671\n",
    "        elif dsid == 'BeijingPM10Quality': dset_id = 3902667\n",
    "        elif dsid == 'LiveFuelMoistureContent': dset_id = 3902716\n",
    "        elif dsid == 'FloodModeling1': dset_id = 3902694\n",
    "        elif dsid == 'FloodModeling2': dset_id = 3902696\n",
    "        elif dsid == 'FloodModeling3': dset_id = 3902698\n",
    "        elif dsid == 'AustraliaRainfall': dset_id = 3902654\n",
    "        elif dsid == 'PPGDalia': dset_id = 3902728\n",
    "        elif dsid == 'IEEEPPG': dset_id = 3902710\n",
    "        elif dsid == 'BIDMCRR' or dsid == 'BIDM32CRR': dset_id = 3902685\n",
    "        elif dsid == 'BIDMCHR' or dsid == 'BIDM32CHR': dset_id = 3902676\n",
    "        elif dsid == 'BIDMCSpO2' or dsid == 'BIDM32CSpO2': dset_id = 3902688\n",
    "        elif dsid == 'NewsHeadlineSentiment': dset_id = 3902718\n",
    "        elif dsid == 'NewsTitleSentiment': dset_id= 3902726\n",
    "        elif dsid == 'Covid3Month': dset_id = 3902690\n",
    "\n",
    "        for split in ['TRAIN', 'TEST']:\n",
    "            url = f\"https://zenodo.org/record/{dset_id}/files/{dsid}_{split}.ts\"\n",
    "            fname = Path(path)/f'{dsid}/{dsid}_{split}.ts'\n",
    "            pv('downloading data...', verbose)\n",
    "            try:\n",
    "                download_data(url, fname, c_key='archive', force_download=force_download, timeout=timeout)\n",
    "            except Exception as inst:\n",
    "                print(inst)\n",
    "                warnings.warn(f'Cannot download {dsid} dataset')\n",
    "                if split_data: return None, None, None, None\n",
    "                else: return None, None, None\n",
    "            pv('...download complete', verbose)\n",
    "            try: \n",
    "                if split == 'TRAIN':\n",
    "                    X_train, y_train = _load_from_tsfile_to_dataframe2(fname)\n",
    "                    X_train = check_X(X_train, coerce_to_numpy=True)\n",
    "                else:\n",
    "                    X_valid, y_valid = _load_from_tsfile_to_dataframe2(fname)\n",
    "                    X_valid = check_X(X_valid, coerce_to_numpy=True)\n",
    "            except Exception as inst:\n",
    "                print(inst)\n",
    "                warnings.warn(f'Cannot create numpy arrays for {dsid} dataset')\n",
    "                if split_data: return None, None, None, None\n",
    "                else: return None, None, None\n",
    "        np.save(f'{full_tgt_dir}/X_train.npy', X_train)\n",
    "        np.save(f'{full_tgt_dir}/y_train.npy', y_train)\n",
    "        np.save(f'{full_tgt_dir}/X_valid.npy', X_valid)\n",
    "        np.save(f'{full_tgt_dir}/y_valid.npy', y_valid)\n",
    "        np.save(f'{full_tgt_dir}/X.npy', concat(X_train, X_valid))\n",
    "        np.save(f'{full_tgt_dir}/y.npy', concat(y_train, y_valid))\n",
    "        del X_train, X_valid, y_train, y_valid\n",
    "        delete_all_in_dir(full_tgt_dir, exception='.npy')\n",
    "        pv('...numpy arrays correctly saved', verbose)\n",
    "\n",
    "    mmap_mode = mode if on_disk else None\n",
    "    X_train = np.load(f'{full_tgt_dir}/X_train.npy', mmap_mode=mmap_mode)\n",
    "    y_train = np.load(f'{full_tgt_dir}/y_train.npy', mmap_mode=mmap_mode)\n",
    "    X_valid = np.load(f'{full_tgt_dir}/X_valid.npy', mmap_mode=mmap_mode)\n",
    "    y_valid = np.load(f'{full_tgt_dir}/y_valid.npy', mmap_mode=mmap_mode)\n",
    "    if Xdtype is not None: \n",
    "        X_train = X_train.astype(Xdtype)\n",
    "        X_valid = X_valid.astype(Xdtype)\n",
    "    if ydtype is not None: \n",
    "        y_train = y_train.astype(ydtype)\n",
    "        y_valid = y_valid.astype(ydtype)\n",
    "\n",
    "    if split_data:\n",
    "        if verbose:\n",
    "            print('X_train:', X_train.shape)\n",
    "            print('y_train:', y_train.shape)\n",
    "            print('X_valid:', X_valid.shape)\n",
    "            print('y_valid:', y_valid.shape, '\\n')\n",
    "        return X_train, y_train, X_valid, y_valid\n",
    "    else:\n",
    "        X = np.load(f'{full_tgt_dir}/X.npy', mmap_mode=mmap_mode)\n",
    "        y = np.load(f'{full_tgt_dir}/y.npy', mmap_mode=mmap_mode)\n",
    "        splits = get_predefined_splits(X_train, X_valid)\n",
    "        if verbose:\n",
    "            print('X      :', X .shape)\n",
    "            print('y      :', y .shape)\n",
    "            print('splits :', coll_repr(splits[0]), coll_repr(splits[1]), '\\n')\n",
    "        return X, y, splits\n",
    "\n",
    "\n",
    "get_regression_data = get_Monash_regression_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset: Covid3Month\n",
      "X      : (201, 1, 84)\n",
      "y      : (201,)\n",
      "splits : (#140) [0,1,2,3,4,5,6,7,8,9...] (#61) [140,141,142,143,144,145,146,147,148,149...] \n",
      "\n"
     ]
    }
   ],
   "source": [
    "dsid = \"Covid3Month\"\n",
    "X_train, y_train, X_valid, y_valid = get_Monash_regression_data(dsid, on_disk=False, split_data=True, force_download=False)\n",
    "X, y, splits = get_Monash_regression_data(dsid, on_disk=True, split_data=False, force_download=False, verbose=True)\n",
    "if X_train is not None: \n",
    "    test_eq(X_train.shape, (140, 1, 84))\n",
    "if X is not None: \n",
    "    test_eq(X.shape, (201, 1, 84))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "hide_input": false
   },
   "outputs": [],
   "source": [
    "#export\n",
    "def get_forecasting_list():\n",
    "    return sorted([\n",
    "        \"Sunspots\", \"Weather\"\n",
    "    ])\n",
    "\n",
    "forecasting_time_series = get_forecasting_list()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "hide_input": false
   },
   "outputs": [],
   "source": [
    "#export\n",
    "def get_forecasting_time_series(dsid, path='./data/forecasting/', force_download=False, verbose=True, **kwargs):\n",
    "    \n",
    "    dsid_list = [fd for fd in forecasting_time_series if fd.lower() == dsid.lower()]\n",
    "    assert len(dsid_list) > 0, f'{dsid} is not a forecasting dataset'\n",
    "    dsid = dsid_list[0]\n",
    "    if dsid == 'Weather': full_tgt_dir = Path(path)/f'{dsid}.csv.zip'\n",
    "    else: full_tgt_dir = Path(path)/f'{dsid}.csv'\n",
    "    pv(f'Dataset: {dsid}', verbose)\n",
    "    if dsid == 'Sunspots': url = \"https://storage.googleapis.com/laurencemoroney-blog.appspot.com/Sunspots.csv\"\n",
    "    elif dsid == 'Weather': url = 'https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip'\n",
    "\n",
    "    try: \n",
    "        pv(\"downloading data...\", verbose)\n",
    "        if force_download: \n",
    "            try: os.remove(full_tgt_dir)\n",
    "            except OSError: pass\n",
    "        download_data(url, full_tgt_dir, force_download=force_download, **kwargs)\n",
    "        pv(f\"...data downloaded. Path = {full_tgt_dir}\", verbose)\n",
    "\n",
    "        if dsid == 'Sunspots': \n",
    "            df = pd.read_csv(full_tgt_dir, parse_dates=['Date'], index_col=['Date'])\n",
    "            return df['Monthly Mean Total Sunspot Number'].asfreq('1M').to_frame()\n",
    "\n",
    "        elif dsid == 'Weather':\n",
    "            # This code comes from a great Keras time-series tutorial notebook (https://www.tensorflow.org/tutorials/structured_data/time_series)\n",
    "            df = pd.read_csv(full_tgt_dir)\n",
    "            df = df[5::6] # slice [start:stop:step], starting from index 5 take every 6th record.\n",
    "\n",
    "            date_time = pd.to_datetime(df.pop('Date Time'), format='%d.%m.%Y %H:%M:%S')\n",
    "\n",
    "            # remove error (negative wind)\n",
    "            wv = df['wv (m/s)']\n",
    "            bad_wv = wv == -9999.0\n",
    "            wv[bad_wv] = 0.0\n",
    "\n",
    "            max_wv = df['max. wv (m/s)']\n",
    "            bad_max_wv = max_wv == -9999.0\n",
    "            max_wv[bad_max_wv] = 0.0\n",
    "\n",
    "            wv = df.pop('wv (m/s)')\n",
    "            max_wv = df.pop('max. wv (m/s)')\n",
    "\n",
    "            # Convert to radians.\n",
    "            wd_rad = df.pop('wd (deg)')*np.pi / 180\n",
    "\n",
    "            # Calculate the wind x and y components.\n",
    "            df['Wx'] = wv*np.cos(wd_rad)\n",
    "            df['Wy'] = wv*np.sin(wd_rad)\n",
    "\n",
    "            # Calculate the max wind x and y components.\n",
    "            df['max Wx'] = max_wv*np.cos(wd_rad)\n",
    "            df['max Wy'] = max_wv*np.sin(wd_rad)\n",
    "\n",
    "            timestamp_s = date_time.map(datetime.timestamp)\n",
    "            day = 24*60*60\n",
    "            year = (365.2425)*day\n",
    "\n",
    "            df['Day sin'] = np.sin(timestamp_s * (2 * np.pi / day))\n",
    "            df['Day cos'] = np.cos(timestamp_s * (2 * np.pi / day))\n",
    "            df['Year sin'] = np.sin(timestamp_s * (2 * np.pi / year))\n",
    "            df['Year cos'] = np.cos(timestamp_s * (2 * np.pi / year))\n",
    "            df.reset_index(drop=True, inplace=True)\n",
    "            return df\n",
    "        else: \n",
    "            return full_tgt_dir\n",
    "    except Exception as inst:\n",
    "        print(inst)\n",
    "        warnings.warn(f\"Cannot download {dsid} dataset\")\n",
    "        return"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "hide_input": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset: Sunspots\n",
      "downloading data...\n",
      "...data downloaded. Path = data/forecasting/Sunspots.csv\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Monthly Mean Total Sunspot Number</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1749-01-31</th>\n",
       "      <td>96.7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1749-02-28</th>\n",
       "      <td>104.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1749-03-31</th>\n",
       "      <td>116.7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1749-04-30</th>\n",
       "      <td>92.8</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1749-05-31</th>\n",
       "      <td>141.7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-03-31</th>\n",
       "      <td>2.5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-04-30</th>\n",
       "      <td>8.9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-05-31</th>\n",
       "      <td>13.2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-06-30</th>\n",
       "      <td>15.9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-07-31</th>\n",
       "      <td>1.6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>3235 rows × 1 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            Monthly Mean Total Sunspot Number\n",
       "Date                                         \n",
       "1749-01-31                               96.7\n",
       "1749-02-28                              104.3\n",
       "1749-03-31                              116.7\n",
       "1749-04-30                               92.8\n",
       "1749-05-31                              141.7\n",
       "...                                       ...\n",
       "2018-03-31                                2.5\n",
       "2018-04-30                                8.9\n",
       "2018-05-31                               13.2\n",
       "2018-06-30                               15.9\n",
       "2018-07-31                                1.6\n",
       "\n",
       "[3235 rows x 1 columns]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts = get_forecasting_time_series(\"sunspots\", force_download=False)\n",
    "test_eq(len(ts), 3235)\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset: Weather\n",
      "downloading data...\n",
      "...data downloaded. Path = data/forecasting/Weather.csv.zip\n",
      "       p (mbar)  T (degC)  Tpot (K)  Tdew (degC)  rh (%)  VPmax (mbar)  \\\n",
      "0        996.50     -8.05    265.38        -8.78   94.40          3.33   \n",
      "1        996.62     -8.88    264.54        -9.77   93.20          3.12   \n",
      "2        996.84     -8.81    264.59        -9.66   93.50          3.13   \n",
      "3        996.99     -9.05    264.34       -10.02   92.60          3.07   \n",
      "4        997.46     -9.63    263.72       -10.65   92.20          2.94   \n",
      "...         ...       ...       ...          ...     ...           ...   \n",
      "70086   1002.18     -0.98    272.01        -5.36   72.00          5.69   \n",
      "70087   1001.40     -1.40    271.66        -6.84   66.29          5.51   \n",
      "70088   1001.19     -2.75    270.32        -6.90   72.90          4.99   \n",
      "70089   1000.65     -2.89    270.22        -7.15   72.30          4.93   \n",
      "70090   1000.11     -3.93    269.23        -8.09   72.60          4.56   \n",
      "\n",
      "       VPact (mbar)  VPdef (mbar)  sh (g/kg)  H2OC (mmol/mol)  rho (g/m**3)  \\\n",
      "0              3.14          0.19       1.96             3.15       1307.86   \n",
      "1              2.90          0.21       1.81             2.91       1312.25   \n",
      "2              2.93          0.20       1.83             2.94       1312.18   \n",
      "3              2.85          0.23       1.78             2.85       1313.61   \n",
      "4              2.71          0.23       1.69             2.71       1317.19   \n",
      "...             ...           ...        ...              ...           ...   \n",
      "70086          4.09          1.59       2.54             4.08       1280.70   \n",
      "70087          3.65          1.86       2.27             3.65       1281.87   \n",
      "70088          3.64          1.35       2.26             3.63       1288.02   \n",
      "70089          3.57          1.37       2.22             3.57       1288.03   \n",
      "70090          3.31          1.25       2.06             3.31       1292.41   \n",
      "\n",
      "             Wx        Wy    max Wx    max Wy       Day sin   Day cos  \\\n",
      "0     -0.204862 -0.046168 -0.614587 -0.138503 -1.776611e-12  1.000000   \n",
      "1     -0.245971 -0.044701 -0.619848 -0.112645  2.588190e-01  0.965926   \n",
      "2     -0.175527  0.039879 -0.614344  0.139576  5.000000e-01  0.866025   \n",
      "3     -0.050000 -0.086603 -0.190000 -0.329090  7.071068e-01  0.707107   \n",
      "4     -0.368202  0.156292 -0.810044  0.343843  8.660254e-01  0.500000   \n",
      "...         ...       ...       ...       ...           ...       ...   \n",
      "70086 -0.855154 -0.160038 -1.336792 -0.250174 -9.990482e-01  0.043619   \n",
      "70087 -0.716196 -0.726267 -1.348134 -1.367090 -9.537170e-01  0.300706   \n",
      "70088 -0.661501  0.257908 -1.453438  0.566672 -8.433914e-01  0.537300   \n",
      "70089 -0.280621 -0.209169 -0.545207 -0.406385 -6.755902e-01  0.737277   \n",
      "70090 -0.516998 -0.215205 -0.923210 -0.384295 -4.617486e-01  0.887011   \n",
      "\n",
      "       Year sin  Year cos  \n",
      "0      0.009332  0.999956  \n",
      "1      0.010049  0.999950  \n",
      "2      0.010766  0.999942  \n",
      "3      0.011483  0.999934  \n",
      "4      0.012199  0.999926  \n",
      "...         ...       ...  \n",
      "70086  0.006183  0.999981  \n",
      "70087  0.006900  0.999976  \n",
      "70088  0.007617  0.999971  \n",
      "70089  0.008334  0.999965  \n",
      "70090  0.009050  0.999959  \n",
      "\n",
      "[70091 rows x 19 columns]\n"
     ]
    }
   ],
   "source": [
    "ts = get_forecasting_time_series(\"weather\", force_download=False)\n",
    "if ts is not None: \n",
    "    test_eq(len(ts), 70091)\n",
    "    print(ts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "Monash_forecasting_list = ['m1_yearly_dataset',\n",
    "                           'm1_quarterly_dataset',\n",
    "                           'm1_monthly_dataset',\n",
    "                           'm3_yearly_dataset',\n",
    "                           'm3_quarterly_dataset',\n",
    "                           'm3_monthly_dataset',\n",
    "                           'm3_other_dataset',\n",
    "                           'm4_yearly_dataset',\n",
    "                           'm4_quarterly_dataset',\n",
    "                           'm4_monthly_dataset',\n",
    "                           'm4_weekly_dataset',\n",
    "                           'm4_daily_dataset',\n",
    "                           'm4_hourly_dataset',\n",
    "                           'tourism_yearly_dataset',\n",
    "                           'tourism_quarterly_dataset',\n",
    "                           'tourism_monthly_dataset',\n",
    "                           'nn5_daily_dataset_with_missing_values',\n",
    "                           'nn5_daily_dataset_without_missing_values',\n",
    "                           'nn5_weekly_dataset',\n",
    "                           'cif_2016_dataset',\n",
    "                           'kaggle_web_traffic_dataset_with_missing_values',\n",
    "                           'kaggle_web_traffic_dataset_without_missing_values',\n",
    "                           'kaggle_web_traffic_weekly_dataset',\n",
    "                           'solar_10_minutes_dataset',\n",
    "                           'solar_weekly_dataset',\n",
    "                           'electricity_hourly_dataset',\n",
    "                           'electricity_weekly_dataset',\n",
    "                           'london_smart_meters_dataset_with_missing_values',\n",
    "                           'london_smart_meters_dataset_without_missing_values',\n",
    "                           'wind_farms_minutely_dataset_with_missing_values',\n",
    "                           'wind_farms_minutely_dataset_without_missing_values',\n",
    "                           'car_parts_dataset_with_missing_values',\n",
    "                           'car_parts_dataset_without_missing_values',\n",
    "                           'dominick_dataset',\n",
    "                           'fred_md_dataset',\n",
    "                           'traffic_hourly_dataset',\n",
    "                           'traffic_weekly_dataset',\n",
    "                           'pedestrian_counts_dataset',\n",
    "                           'hospital_dataset',\n",
    "                           'covid_deaths_dataset',\n",
    "                           'kdd_cup_2018_dataset_with_missing_values',\n",
    "                           'kdd_cup_2018_dataset_without_missing_values',\n",
    "                           'weather_dataset',\n",
    "                           'sunspot_dataset_with_missing_values',\n",
    "                           'sunspot_dataset_without_missing_values',\n",
    "                           'saugeenday_dataset',\n",
    "                           'us_births_dataset',\n",
    "                           'elecdemand_dataset',\n",
    "                           'solar_4_seconds_dataset',\n",
    "                           'wind_4_seconds_dataset',\n",
    "                           'Sunspots', 'Weather']\n",
    "\n",
    "\n",
    "forecasting_list = Monash_forecasting_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "\n",
    "## Original code available at: https://github.com/rakshitha123/TSForecasting\n",
    "# This repository contains the implementations related to the experiments of a set of publicly available datasets that are used in \n",
    "# the time series forecasting research space.\n",
    "\n",
    "# The benchmark datasets are available at: https://zenodo.org/communities/forecasting. For more details, please refer to our website: \n",
    "# https://forecastingdata.org/ and paper: https://arxiv.org/abs/2105.06643.\n",
    "\n",
    "# Citation: \n",
    "# @misc{godahewa2021monash,\n",
    "# author=\"Godahewa, Rakshitha and Bergmeir, Christoph and Webb, Geoffrey I. and Hyndman, Rob J. and Montero-Manso, Pablo\",\n",
    "# title=\"Monash Time Series Forecasting Archive\",\n",
    "# howpublished =\"\\url{https://arxiv.org/abs/2105.06643}\",\n",
    "# year=\"2021\"\n",
    "# }\n",
    "\n",
    "\n",
    "# Converts the contents in a .tsf file into a dataframe and returns it along with other meta-data of the dataset: frequency, horizon, whether the dataset contains missing values and whether the series have equal lengths\n",
    "#\n",
    "# Parameters\n",
    "# full_file_path_and_name - complete .tsf file path\n",
    "# replace_missing_vals_with - a term to indicate the missing values in series in the returning dataframe\n",
    "# value_column_name - Any name that is preferred to have as the name of the column containing series values in the returning dataframe\n",
    "def convert_tsf_to_dataframe(full_file_path_and_name, replace_missing_vals_with = 'NaN', value_column_name = \"series_value\"):\n",
    "    col_names = []\n",
    "    col_types = []\n",
    "    all_data = {}\n",
    "    line_count = 0\n",
    "    frequency = None\n",
    "    forecast_horizon = None\n",
    "    contain_missing_values = None\n",
    "    contain_equal_length = None\n",
    "    found_data_tag = False\n",
    "    found_data_section = False\n",
    "    started_reading_data_section = False\n",
    "\n",
    "    with open(full_file_path_and_name, 'r', encoding='cp1252') as file:\n",
    "        for line in file:\n",
    "            # Strip white space from start/end of line\n",
    "            line = line.strip()\n",
    "\n",
    "            if line:\n",
    "                if line.startswith(\"@\"): # Read meta-data\n",
    "                    if not line.startswith(\"@data\"):\n",
    "                        line_content = line.split(\" \")\n",
    "                        if line.startswith(\"@attribute\"):\n",
    "                            if (len(line_content) != 3):  # Attributes have both name and type\n",
    "                                raise TsFileParseException(\"Invalid meta-data specification.\")\n",
    "\n",
    "                            col_names.append(line_content[1])\n",
    "                            col_types.append(line_content[2])\n",
    "                        else:\n",
    "                            if len(line_content) != 2:  # Other meta-data have only values\n",
    "                                raise TsFileParseException(\"Invalid meta-data specification.\")\n",
    "\n",
    "                            if line.startswith(\"@frequency\"):\n",
    "                                frequency = line_content[1]\n",
    "                            elif line.startswith(\"@horizon\"):\n",
    "                                forecast_horizon = int(line_content[1])\n",
    "                            elif line.startswith(\"@missing\"):\n",
    "                                contain_missing_values = bool(distutils.util.strtobool(line_content[1]))\n",
    "                            elif line.startswith(\"@equallength\"):\n",
    "                                contain_equal_length = bool(distutils.util.strtobool(line_content[1]))\n",
    "\n",
    "                    else:\n",
    "                        if len(col_names) == 0:\n",
    "                            raise TsFileParseException(\"Missing attribute section. Attribute section must come before data.\")\n",
    "\n",
    "                        found_data_tag = True\n",
    "                elif not line.startswith(\"#\"):\n",
    "                    if len(col_names) == 0:\n",
    "                        raise TsFileParseException(\"Missing attribute section. Attribute section must come before data.\")\n",
    "                    elif not found_data_tag:\n",
    "                        raise TsFileParseException(\"Missing @data tag.\")\n",
    "                    else:\n",
    "                        if not started_reading_data_section:\n",
    "                            started_reading_data_section = True\n",
    "                            found_data_section = True\n",
    "                            all_series = []\n",
    "\n",
    "                            for col in col_names:\n",
    "                                all_data[col] = []\n",
    "\n",
    "                        full_info = line.split(\":\")\n",
    "\n",
    "                        if len(full_info) != (len(col_names) + 1):\n",
    "                            raise TsFileParseException(\"Missing attributes/values in series.\")\n",
    "\n",
    "                        series = full_info[len(full_info) - 1]\n",
    "                        series = series.split(\",\")\n",
    "\n",
    "                        if(len(series) == 0):\n",
    "                            raise TsFileParseException(\"A given series should contains a set of comma separated numeric values. At least one numeric value should be there in a series. Missing values should be indicated with ? symbol\")\n",
    "\n",
    "                        numeric_series = []\n",
    "\n",
    "                        for val in series:\n",
    "                            if val == \"?\":\n",
    "                                numeric_series.append(replace_missing_vals_with)\n",
    "                            else:\n",
    "                                numeric_series.append(float(val))\n",
    "\n",
    "                        if (numeric_series.count(replace_missing_vals_with) == len(numeric_series)):\n",
    "                            raise TsFileParseException(\"All series values are missing. A given series should contains a set of comma separated numeric values. At least one numeric value should be there in a series.\")\n",
    "\n",
    "                        all_series.append(pd.Series(numeric_series).array)\n",
    "\n",
    "                        for i in range(len(col_names)):\n",
    "                            att_val = None\n",
    "                            if col_types[i] == \"numeric\":\n",
    "                                att_val = int(full_info[i])\n",
    "                            elif col_types[i] == \"string\":\n",
    "                                att_val = str(full_info[i])\n",
    "                            elif col_types[i] == \"date\":\n",
    "                                att_val = datetime.strptime(full_info[i], '%Y-%m-%d %H-%M-%S')\n",
    "                            else:\n",
    "                                raise TsFileParseException(\"Invalid attribute type.\") # Currently, the code supports only numeric, string and date types. Extend this as required.\n",
    "\n",
    "                            if(att_val == None):\n",
    "                                raise TsFileParseException(\"Invalid attribute value.\")\n",
    "                            else:\n",
    "                                all_data[col_names[i]].append(att_val)\n",
    "\n",
    "                line_count = line_count + 1\n",
    "\n",
    "        if line_count == 0:\n",
    "            raise TsFileParseException(\"Empty file.\")\n",
    "        if len(col_names) == 0:\n",
    "            raise TsFileParseException(\"Missing attribute section.\")\n",
    "        if not found_data_section:\n",
    "            raise TsFileParseException(\"Missing series information under data section.\")\n",
    "\n",
    "        all_data[value_column_name] = all_series\n",
    "        loaded_data = pd.DataFrame(all_data)\n",
    "\n",
    "        return loaded_data, frequency, forecast_horizon, contain_missing_values, contain_equal_length"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# export\n",
    "\n",
    "def get_Monash_forecasting_data(dsid, path='./data/forecasting/', force_download=False, remove_from_disk=False, verbose=True):\n",
    "\n",
    "    pv(f'Dataset: {dsid}', verbose)\n",
    "    dsid = dsid.lower()\n",
    "    assert dsid in Monash_forecasting_list, f'{dsid} not available in Monash_forecasting_list'\n",
    "\n",
    "    if dsid == 'm1_yearly_dataset': url = 'https://zenodo.org/record/4656193/files/m1_yearly_dataset.zip'\n",
    "    elif dsid == 'm1_quarterly_dataset': url = 'https://zenodo.org/record/4656154/files/m1_quarterly_dataset.zip'\n",
    "    elif dsid == 'm1_monthly_dataset': url = 'https://zenodo.org/record/4656159/files/m1_monthly_dataset.zip'\n",
    "    elif dsid == 'm3_yearly_dataset': url = 'https://zenodo.org/record/4656222/files/m3_yearly_dataset.zip'\n",
    "    elif dsid == 'm3_quarterly_dataset': url = 'https://zenodo.org/record/4656262/files/m3_quarterly_dataset.zip'\n",
    "    elif dsid == 'm3_monthly_dataset': url = 'https://zenodo.org/record/4656298/files/m3_monthly_dataset.zip'\n",
    "    elif dsid == 'm3_other_dataset': url = 'https://zenodo.org/record/4656335/files/m3_other_dataset.zip'\n",
    "    elif dsid == 'm4_yearly_dataset': url = 'https://zenodo.org/record/4656379/files/m4_yearly_dataset.zip'\n",
    "    elif dsid == 'm4_quarterly_dataset': url = 'https://zenodo.org/record/4656410/files/m4_quarterly_dataset.zip'\n",
    "    elif dsid == 'm4_monthly_dataset': url = 'https://zenodo.org/record/4656480/files/m4_monthly_dataset.zip'\n",
    "    elif dsid == 'm4_weekly_dataset': url = 'https://zenodo.org/record/4656522/files/m4_weekly_dataset.zip'\n",
    "    elif dsid == 'm4_daily_dataset': url = 'https://zenodo.org/record/4656548/files/m4_daily_dataset.zip'\n",
    "    elif dsid == 'm4_hourly_dataset': url = 'https://zenodo.org/record/4656589/files/m4_hourly_dataset.zip'\n",
    "    elif dsid == 'tourism_yearly_dataset': url = 'https://zenodo.org/record/4656103/files/tourism_yearly_dataset.zip'\n",
    "    elif dsid == 'tourism_quarterly_dataset': url = 'https://zenodo.org/record/4656093/files/tourism_quarterly_dataset.zip'\n",
    "    elif dsid == 'tourism_monthly_dataset': url = 'https://zenodo.org/record/4656096/files/tourism_monthly_dataset.zip'\n",
    "    elif dsid == 'nn5_daily_dataset_with_missing_values': url = 'https://zenodo.org/record/4656110/files/nn5_daily_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'nn5_daily_dataset_without_missing_values': url = 'https://zenodo.org/record/4656117/files/nn5_daily_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'nn5_weekly_dataset': url = 'https://zenodo.org/record/4656125/files/nn5_weekly_dataset.zip'\n",
    "    elif dsid == 'cif_2016_dataset': url = 'https://zenodo.org/record/4656042/files/cif_2016_dataset.zip'\n",
    "    elif dsid == 'kaggle_web_traffic_dataset_with_missing_values': url = 'https://zenodo.org/record/4656080/files/kaggle_web_traffic_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'kaggle_web_traffic_dataset_without_missing_values': url = 'https://zenodo.org/record/4656075/files/kaggle_web_traffic_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'kaggle_web_traffic_weekly': url = 'https://zenodo.org/record/4656664/files/kaggle_web_traffic_weekly_dataset.zip'\n",
    "    elif dsid == 'solar_10_minutes_dataset': url = 'https://zenodo.org/record/4656144/files/solar_10_minutes_dataset.zip'\n",
    "    elif dsid == 'solar_weekly_dataset': url = 'https://zenodo.org/record/4656151/files/solar_weekly_dataset.zip'\n",
    "    elif dsid == 'electricity_hourly_dataset': url = 'https://zenodo.org/record/4656140/files/electricity_hourly_dataset.zip'\n",
    "    elif dsid == 'electricity_weekly_dataset': url = 'https://zenodo.org/record/4656141/files/electricity_weekly_dataset.zip'\n",
    "    elif dsid == 'london_smart_meters_dataset_with_missing_values': url = 'https://zenodo.org/record/4656072/files/london_smart_meters_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'london_smart_meters_dataset_without_missing_values': url = 'https://zenodo.org/record/4656091/files/london_smart_meters_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'wind_farms_minutely_dataset_with_missing_values': url = 'https://zenodo.org/record/4654909/files/wind_farms_minutely_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'wind_farms_minutely_dataset_without_missing_values': url = 'https://zenodo.org/record/4654858/files/wind_farms_minutely_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'car_parts_dataset_with_missing_values': url = 'https://zenodo.org/record/4656022/files/car_parts_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'car_parts_dataset_without_missing_values': url = 'https://zenodo.org/record/4656021/files/car_parts_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'dominick_dataset': url = 'https://zenodo.org/record/4654802/files/dominick_dataset.zip'\n",
    "    elif dsid == 'fred_md_dataset': url = 'https://zenodo.org/record/4654833/files/fred_md_dataset.zip'\n",
    "    elif dsid == 'traffic_hourly_dataset': url = 'https://zenodo.org/record/4656132/files/traffic_hourly_dataset.zip'\n",
    "    elif dsid == 'traffic_weekly_dataset': url = 'https://zenodo.org/record/4656135/files/traffic_weekly_dataset.zip'\n",
    "    elif dsid == 'pedestrian_counts_dataset': url = 'https://zenodo.org/record/4656626/files/pedestrian_counts_dataset.zip'\n",
    "    elif dsid == 'hospital_dataset': url = 'https://zenodo.org/record/4656014/files/hospital_dataset.zip'\n",
    "    elif dsid == 'covid_deaths_dataset': url = 'https://zenodo.org/record/4656009/files/covid_deaths_dataset.zip'\n",
    "    elif dsid == 'kdd_cup_2018_dataset_with_missing_values': url = 'https://zenodo.org/record/4656719/files/kdd_cup_2018_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'kdd_cup_2018_dataset_without_missing_values': url = 'https://zenodo.org/record/4656756/files/kdd_cup_2018_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'weather_dataset': url = 'https://zenodo.org/record/4654822/files/weather_dataset.zip'\n",
    "    elif dsid == 'sunspot_dataset_with_missing_values': url = 'https://zenodo.org/record/4654773/files/sunspot_dataset_with_missing_values.zip'\n",
    "    elif dsid == 'sunspot_dataset_without_missing_values': url = 'https://zenodo.org/record/4654722/files/sunspot_dataset_without_missing_values.zip'\n",
    "    elif dsid == 'saugeenday_dataset': url = 'https://zenodo.org/record/4656058/files/saugeenday_dataset.zip'\n",
    "    elif dsid == 'us_births_dataset': url = 'https://zenodo.org/record/4656049/files/us_births_dataset.zip'\n",
    "    elif dsid == 'elecdemand_dataset': url = 'https://zenodo.org/record/4656069/files/elecdemand_dataset.zip'\n",
    "    elif dsid == 'solar_4_seconds_dataset': url = 'https://zenodo.org/record/4656027/files/solar_4_seconds_dataset.zip'\n",
    "    elif dsid == 'wind_4_seconds_dataset': url = 'https://zenodo.org/record/4656032/files/wind_4_seconds_dataset.zip'\n",
    "\n",
    "    path = Path(path)\n",
    "    full_path = path/f'{dsid}.tsf'\n",
    "    if not full_path.exists() or force_download: \n",
    "        try: \n",
    "            decompress_from_url(url, target_dir=path, verbose=verbose)\n",
    "        except Exception as inst:\n",
    "            print(inst)\n",
    "    pv(\"converting dataframe to numpy array...\", verbose)\n",
    "    data, frequency, forecast_horizon, contain_missing_values, contain_equal_length = convert_tsf_to_dataframe(full_path)\n",
    "    X = to3d(stack_pad(data['series_value']))\n",
    "    pv(\"...dataframe converted to numpy array\", verbose)\n",
    "    pv(f'\\nX.shape: {X.shape}', verbose)  \n",
    "    pv(f'freq: {frequency}', verbose)  \n",
    "    pv(f'forecast_horizon: {forecast_horizon}', verbose)  \n",
    "    pv(f'contain_missing_values: {contain_missing_values}', verbose)  \n",
    "    pv(f'contain_equal_length: {contain_equal_length}', verbose=verbose)\n",
    "    if remove_from_disk: os.remove(full_path)\n",
    "    return X\n",
    "\n",
    "get_forecasting_data = get_Monash_forecasting_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset: m1_yearly_dataset\n",
      "downloading data...\n",
      "...data downloaded\n",
      "decompressing data...\n",
      "...data decompressed\n",
      "converting dataframe to numpy array...\n",
      "...dataframe converted to numpy array\n",
      "\n",
      "X.shape: (181, 1, 58)\n",
      "freq: yearly\n",
      "forecast_horizon: 6\n",
      "contain_missing_values: False\n",
      "contain_equal_length: False\n"
     ]
    }
   ],
   "source": [
    "dsid = 'm1_yearly_dataset'\n",
    "X = get_Monash_forecasting_data(dsid, force_download=False)\n",
    "if X is not None: \n",
    "    test_eq(X.shape, (181, 1, 58))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "hide_input": false
   },
   "outputs": [],
   "source": [
    "#hide\n",
    "from tsai.imports import create_scripts\n",
    "from tsai.export import get_nb_name\n",
    "nb_name = get_nb_name()\n",
    "create_scripts(nb_name);"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
